#ifndef RP2MATRIX4_H
#define RP2MATRIX4_H

#include "Rp2System.h"
#include "Rp2Math.h"
#include "Rp2Vector3.h"
#include "Rp2Vector4.h"
#include "Rp2Matrix3.h"
namespace Rp2
{

// Matrix operations are applied on the right.  For example, given a matrix M
// and a vector V, matrix-times-vector is V*M.  That is, V is treated as a
// row vector.

template <class Real>
class Matrix4
{
public:
	// if bzero == true, create zero matrix,
	// otherwise identity matrix.
	Matrix4(bool bZero = true);

	Matrix4(Real f00, Real f01, Real f02, Real f03,
			Real f10, Real f11, Real f12, Real f13,
			Real f20, Real f21, Real f22, Real f23,
			Real f30, Real f31, Real f32, Real f33);

	// copy constructor;
	Matrix4(const Matrix4& rkM);

	// Create rotation matrices (positive angle - counterclockwise).  The
	// angle must be in radians, not degrees.
	Matrix4(const Vector3<Real>& rkAxis, Real fAngleRad);	



	// member access
	inline Real& operator[] (int iEntry);
	inline operator const Real* () const;
	inline operator Real* ();

	// comparison
	bool operator== (const Matrix4& rkM) const;
	bool operator!= (const Matrix4& rkM) const;
	bool operator<  (const Matrix4& rkM) const;
	bool operator<= (const Matrix4& rkM) const;
	bool operator>  (const Matrix4& rkM) const;
	bool operator>= (const Matrix4& rkM) const;

	// arithmetic operations
	inline Matrix4 operator* (const Matrix4& rkM) const;
	inline Matrix4 operator* (Real fScalar) const;

	// transformation
	inline Vector4<Real> operator* (const Vector4<Real>& rkV) const; //M * v^t

	// other operations
	Matrix4 Transpose() const; //M^t
	Matrix4 Inverse() const;
	Matrix4& FromAxisAngle(const Vector3<Real>& rkAxis, Real fAngleRad);
	Matrix4& MakeZero();
	Matrix4& MakeIdentity();
	Matrix4& MakeHomogeneous(Matrix3<Real>& rkM3);

	// special matrix
	static const Matrix4 ZERO;
	static const Matrix4 IDENTITY;

	// print the matrix
	void Print();

protected:
	Real m_afTuple[16];

	// support operations
	int CompareArrays(const Matrix4& rkM) const;
	
};

// c * M
template <class Real>
inline Matrix4<Real> operator* (Real fScalar, const Matrix4<Real>& rkM);

// v * M
template <class Real>
inline Vector4<Real> operator* (const Vector4<Real>& rkV, 
	const Matrix4<Real>& rkM);

#include "Rp2Matrix4.inl"

typedef Matrix4<float> Matrix4f;
typedef Matrix4<double> Matrix4d;

}


#endif